	include	Common.asm
; ==========================================================
	public	LoadPCX
; ==========================================================
DataSeg		segment para public 'data'
	; Pcx File Info
	PcxHandle	dw	?
	PcxWidth	dw	?
	PcxHeight	dw	?
	PcxSize		dw	?
	; Buffer
	Buffer		db	?
DataSeg		ends
; ==========================================================
CodeSeg		segment para public 'code'

; ----------------------------------------------------------
; LoadPCX: Load PCX File
; ----------------------------------------------------------
; Input:
;	bx	Source File String
;	es	Dest Address
; ----------------------------------------------------------
LoadPCX 	proc    near
	assume	ds:DataSeg, cs:CodeSeg

	; Open File
	call	OpenFile	;

	; Read File
	call	ReadFile

	; Close File
	call	CloseFile	;

	ret
LoadPCX	 	endp

; ----------------------------------------------------------
; Open PCX image File & Get Width, Height
; Input:
;	bx	FileName
; ----------------------------------------------------------
OpenFile	proc	near
	push	ax
	push	bx
	push	cx
	push	dx

	; Open File
	mov	ah, 3dh		; ah = 3dh - Open Disk File
	mov	al, 0h		; al = 0 - Read Only
	mov	dx, bx		; dx = FileName
	int	21h		; 
	mov	PcxHandle, ax	; PcxHandle = ax

	; Seek File - Width, Height
	mov	ah, 42h		; ah = 42h - File Seek
	mov	al, 0h		; al = 0h - offset from beginning of file
	mov	bx, PcxHandle	; bx = PcxHandle - file handle
	mov	cx, 0h		; cx = 0h - offset in bytes 
	mov	dx, 8h		; dx = 8h - offset = cx:dx
	int	21h

	; Read File - Width
	mov	ah, 3fh		; ah = 3fh - Read from file with handle
	mov	bx, PcxHandle	; bx = PcxHandle - file handle
	mov	cx, 2h		; cx = number of bytes to read
	lea	dx, PcxWidth	; dx = PcxWidth - ds:dx = Address of buffer
	int	21h
	add	PcxWidth, 01h	; 

	; PcxWidth must be Even Number!!!
	mov	ax, PcxWidth	; 
	and	ax, 01h		; ax = PcxWidth & 0x1
	cmp	ax, 01h		;
	jb	ReadHeight	; jump to ReadHeight, if ax < 1 (ax=0)
	add	PcxWidth, 01h	; PcxWidth must be Even Number!!!

ReadHeight:
	; Read File - Height
	mov	ah, 3fh		; ah = 3fh - Read from file with handle
	mov	bx, PcxHandle	; bx = PcxHandle - file handle
	mov	cx, 2h		; cx = number of bytes to read
	lea	dx, PcxHeight	; dx = PcxHeight - ds:dx = Address of buffer
	int	21h
	add	PcxHeight, 01h	;

	; Set PcxSize = PcxWidth * PcxHeight
	mov	ax, PcxWidth	;
	mul	PcxHeight	;
	mov	PcxSize, ax	; PcxSize = PcxWidth * PcxHeight
	
	; Seek File - Data part
	mov	ah, 42h		; ah = 42h - File Seek
	mov	al, 0h		; al = 0h - offset from beginning of file
	mov	bx, PcxHandle	; bx = PcxHandle - file handle
	mov	cx, 0h		; cx = 0 - offset in bytes 
	mov	dx, 80h		; dx = 80h - offset = cx:dx
	int	21h

	pop	dx
	pop	cx
	pop	bx
	pop	ax

	ret
OpenFile	endp

; ----------------------------------------------------------
; Close File
; ----------------------------------------------------------
CloseFile	proc	near
	push	ax
	push	bx
	
	mov	ah, 3eh		; ah = 3eh - Close a file with handle
	mov	bx, PcxHandle	; bx = PcxHandle
	int	21h		;

	pop	bx
	pop	ax
	ret
CloseFile	endp

; ----------------------------------------------------------
; Read File
; Input:
;	es:bx		Dest Address
; ----------------------------------------------------------
ReadFile	proc	near
	local	CountBuffer: byte
	local	ColorBuffer: byte

	push	ax
	push	bx
	push	cx
	push	dx

	mov	bx, 0h		; Reset bx

ReadFileCount:
	; Read Pixel Count
	call	Read1Byte
	mov	CountBuffer, al

	; CountBuffer > c0H ?
	cmp	CountBuffer, 0c0h
	ja	ReadFileColor

	; CountBuffer <= c0H ?
	mov	ColorBuffer, al
	mov	CountBuffer, 01h
	jmp	WriteBuffer

ReadFileColor:
	sub	CountBuffer, 0c0h	; CountBuffer = CountBuffer - 0c0h

	; Read Color
	call	Read1Byte
	mov	ColorBuffer, al

WriteBuffer:
	mov	ch, 0h
	mov	cl, CountBuffer
	mov	dl, ColorBuffer

WriteBufferLoop:
	mov	es:[bx], dl
	inc	bx
	Loop	WriteBufferLoop

	cmp	bx, PcxSize		; bx > PcxSize ?
	jb	ReadFileCount

	; Load Palette
	call	Read1Byte		; Read 1 Byte	
	call	LoadPalette

	pop	dx
	pop	cx
	pop	bx
	pop	ax

	ret
ReadFile	endp


; ----------------------------------------------------------
; Load Palette
; Input:
;	es:bx		Dest Address
; ----------------------------------------------------------
LoadPalette	proc	near
	push	ax
	push	bx
	push	cx
	push	dx

	; Read 256 colors from file
	mov	cx, 256		; cx = 256
ReadPaletteEntry:
	cmp	cx, 0		; cx > 0 ?
	jz	ExitRead	; jump to ExitRead, if cx = 0

	dec	cx		; cx = cx - 1

	mov	dx, 3c8h
	mov	al, 0ffh
	sub	al, cl
	out	dx, al

	mov	dx, 3c9h

	call	Read1Byte	; Read 1 Byte
	shr	al, 1
	shr	al, 1
	out	dx, al
	
	call	Read1Byte	; Read 1 Byte
	shr	al, 1
	shr	al, 1
	out	dx, al
	
	call	Read1Byte	; Read 1 Byte
	shr	al, 1
	shr	al, 1
	out	dx, al
	
	jmp	ReadPaletteEntry
	
ExitRead:
	; Restore Register
	pop	dx
	pop	cx
	pop	bx
	pop	ax

	ret
LoadPalette	endp


; ----------------------------------------------------------
; Read 1 Byte
; Output:
;	ax		Output Data
; ----------------------------------------------------------
Read1Byte	proc	near
	push	bx
	push	cx
	push	dx

	mov	ax, 3f00h		; ah = 3fh - Read from file with handle
	mov	bx, PcxHandle		; bx = PcxHandle - file handle
	mov	cx, 01h			; cx = number of bytes to read
	lea	dx, Buffer		; dx = Buffer - ds:dx = Address of buffer
	int	21h

	mov	ah, 0h			; 
	mov	al, Buffer		; 

	pop	dx
	pop	cx
	pop	bx
	ret
Read1Byte	endp

CodeSeg		ends

		end

